package org.darcy.config.shiro.credentials;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.darcy.config.shiro.EhcacheService;
import org.darcy.entity.SysUser;
import org.darcy.service.SysConfigService;
import org.darcy.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

/**
 * Shiro-密码输入错误的状态下重试次数的匹配管理
 */
public class RetryLimitCredentialsMatcher extends CredentialsMatcher {

	@Autowired
	private EhcacheService EhcacheService;

	/**
	 * 用户登录次数计数 redisKey 前缀
	 */
	private static final String SHIRO_LOGIN_COUNT = "shiro_login_count_";
	/**
	 * 用户登录是否被锁定 一小时 redisKey 前缀
	 */
	private static final String SHIRO_IS_LOCK = "shiro_is_lock_";
	/**
	 * 登录失败时重试的次数，默认5次
	 */
	private static final int DEFAULT_RETRY_NUM = 5;
	/**
	 * session有效期，默认1小时
	 */
	private static final int DEFAULT_SESSIONTIME_OUT = 1;
	/**
	 * session有效期的时间单位，默认小时
	 */
	private static final TimeUnit DEFAULT_SESSIONTIME_OUT_UNIT = TimeUnit.HOURS;

	@Autowired
	private SysUserService userService;

	@Autowired
	private SysConfigService configService;

	@Override
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		SysUser user = (SysUser) info.getPrincipals().getPrimaryPrincipal();
		String username = user.getUsername();
		// 访问一次，计数一次
		String loginCountKey = SHIRO_LOGIN_COUNT + username;
		String isLockKey = SHIRO_IS_LOCK + username;
		EhcacheService.increment(loginCountKey);

		if (EhcacheService.hasKey(isLockKey)) {
			throw new ExcessiveAttemptsException("帐号[" + username + "]已被锁定，禁止登录，30分钟后再尝试！");
		}

		Map<String, Object> configs = configService.getConfigs();
		Object loginRetryNumObj = configs.get("loginRetryNum");
		int loginRetryNum = StringUtils.isEmpty(loginRetryNumObj) ? DEFAULT_RETRY_NUM
				: Integer.parseInt(String.valueOf(loginRetryNumObj));

		String loginCount = String.valueOf(EhcacheService.getLoginCount(loginCountKey));
		int retryCount = ((loginRetryNum + 1) - Integer.parseInt(loginCount));
		if (retryCount <= 0) {
			EhcacheService.set(isLockKey, "Lock");
			throw new ExcessiveAttemptsException("由于密码输入错误次数过多，帐号[" + username + "]已被禁止登录！");
		}

		boolean matches = super.doCredentialsMatch(token, info);
		if (!matches) {
			throw new AccountException("帐号或密码不正确！您还剩" + retryCount + "次重试的机会");
		}
		EhcacheService.delete(loginCountKey);
		try {
			userService.updateUserLastLoginInfo(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return true;
	}
}
